[iOS] Fix VoiceOver dropping child labels on layouts with SemanticProperties.Hint or TapGestureRecognizer#35590
Conversation
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 35590Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 35590" |
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 3 findings
See inline comments for details.
kubaflo
left a comment
There was a problem hiding this comment.
Could you please check the ai's suggestions?
|
/review -b feature/refactor-copilot-yml |
MauiBot
left a comment
There was a problem hiding this comment.
Expert Review — 1 findings
See inline comments for details.
|
|
/review -b feature/refactor-copilot-yml -p ios |
🤖 AI Summary
📊 Review Session —
|
| Test | Without Fix (expect FAIL) | With Fix (expect PASS) |
|---|---|---|
📱 AccessibilityTests (LayoutWithHintAndChildLabels_SynthesizesAccessibilityLabel, LayoutWithTapGesture_SetsShouldGroupAccessibilityChildren, AccessibilityActivate_InvokesTapGesture) Category=Accessibility |
✅ FAIL — 337s | ✅ PASS — 189s |
🔴 Without fix — 📱 AccessibilityTests (LayoutWithHintAndChildLabels_SynthesizesAccessibilityLabel, LayoutWithTapGesture_SetsShouldGroupAccessibilityChildren, AccessibilityActivate_InvokesTapGesture): FAIL ✅ · 337s
(truncated to last 15,000 chars)
:40:28.8543270] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543310] 2026-05-29 07:40:28.850601-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543350] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543390] 2026-05-29 07:40:28.850673-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass17_0`1.<<CreateHandlerAndAddToWindow>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543430] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543570] 2026-05-29 07:40:28.850750-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543610] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543660] 2026-05-29 07:40:28.850870-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543690] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543730] 2026-05-29 07:40:28.851040-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.AccessibilityTests.Issue34380Tests.LayoutWithTapGesture_SetsShouldGroupAccessibilityChildren()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543760] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543800] Execution time: 0.1972545
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543920] Test trait name: Category
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8543970] value: Accessibility
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544060] 2026-05-29 07:40:28.851137-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] 2) [FAIL] AccessibilityActivate on a layout with TapGestureRecognizer fires the gesture Test name: AccessibilityActivate on a layout with TapGestureRecognizer fires the gesture
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544130] 2026-05-29 07:40:28.851220-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Assembly: [Microsoft.Maui.Controls.DeviceTests, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544180] 2026-05-29 07:40:28.851313-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Exception messages: AccessibilityActivate should report that the activation was handled. Exception stack traces: at Microsoft.Maui.DeviceTests.AccessibilityTests.Issue34380Tests.<>c__DisplayClass3_0.<<AccessibilityActivate_InvokesTapGesture>b__1>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544210] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544260] 2026-05-29 07:40:28.851385-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass17_1`1.<<CreateHandlerAndAddToWindow>b__1>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544390] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544440] 2026-05-29 07:40:28.851473-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass31_0`1.<<SetupWindowForTests>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544470] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544510] 2026-05-29 07:40:28.851550-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass31_0`1.<<SetupWindowForTests>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544550] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544590] 2026-05-29 07:40:28.851638-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544620] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544750] 2026-05-29 07:40:28.851729-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544790] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544830] 2026-05-29 07:40:28.851813-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass17_0`1.<<CreateHandlerAndAddToWindow>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544880] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544910] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8544940] 2026-05-29 07:40:28.851920-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545070] 2026-05-29 07:40:28.852026-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545120] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545150] at Microsoft.Maui.DeviceTests.AccessibilityTests.Issue34380Tests.AccessibilityActivate_InvokesTapGesture()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545190] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545220] Execution time: 0.6023928
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545270] 2026-05-29 07:40:28.852103-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Test trait name: Category
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545300] value: Accessibility
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545340] 2026-05-29 07:40:28.852202-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] 3) [FAIL] Layout with Hint and child Labels synthesizes a combined AccessibilityLabel Test name: Layout with Hint and child Labels synthesizes a combined AccessibilityLabel
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545370] 2026-05-29 07:40:28.852396-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Assembly: [Microsoft.Maui.Controls.DeviceTests, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545490] 2026-05-29 07:40:28.852498-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Exception messages: AccessibilityLabel should be synthesized from child Labels. Exception stack traces: at Microsoft.Maui.DeviceTests.AccessibilityTests.Issue34380Tests.<>c__DisplayClass1_0.<<LayoutWithHintAndChildLabels_SynthesizesAccessibilityLabel>b__0>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545540] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545590] 2026-05-29 07:40:28.852592-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass17_1`1.<<CreateHandlerAndAddToWindow>b__1>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545620] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545760] 2026-05-29 07:40:28.852853-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass31_0`1.<<SetupWindowForTests>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545800] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545840] 2026-05-29 07:40:28.852972-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass31_0`1.<<SetupWindowForTests>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545880] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545910] 2026-05-29 07:40:28.853093-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545950] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8545980] 2026-05-29 07:40:28.853231-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546120] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546160] 2026-05-29 07:40:28.853344-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.DeviceTests.ControlsHandlerTestBase.<>c__DisplayClass17_0`1.<<CreateHandlerAndAddToWindow>b__0>d[[Microsoft.Maui.Handlers.IWindowHandler, Microsoft.Maui, Version=10.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546210] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546240] 2026-05-29 07:40:28.853461-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass3_0.<<DispatchAsync>b__0>d.MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546280] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546320] 2026-05-29 07:40:28.853608-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] at Microsoft.Maui.Dispatching.DispatcherExtensions.<>c__DisplayClass2_0`1.<<DispatchAsync>b__0>d[[System.Boolean, System.Private.CoreLib, Version=10.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].MoveNext()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546350] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546410] at Microsoft.Maui.DeviceTests.AccessibilityTests.Issue34380Tests.LayoutWithHintAndChildLabels_SynthesizesAccessibilityLabel()
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546450] --- End of stack trace from previous location ---
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546490] 2026-05-29 07:40:28.853712-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Execution time: 0.235509
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546530] Test trait name: Category
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546570] value: Accessibility
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8546600] 2026-05-29 07:40:28.854287-0700 Microsoft.Maui.Controls.DeviceTests[6878:45925] Tests run: 8 Passed: 5 Inconclusive: 0 Failed: 3 Ignored: 0
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8588370] 2026-05-29 07:40:28.858636-0700 Microsoft.Maui.Controls.DeviceTests[6878:45379] Xml file was written to the provided writer.
�[40m�[37mdbug�[39m�[22m�[49m: [07:40:28.8590130] 2026-05-29 07:40:28.858847-0700 Microsoft.Maui.Controls.DeviceTests[6878:45379] Tests run: 450 Passed: 5 Inconclusive: 0 Failed: 3 Ignored: 442
�[40m�[37mdbug�[39m�[22m�[49m: ==================== End of ApplicationLog ====================
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[32minfo�[39m�[22m�[49m: Uninstalling the application 'com.microsoft.maui.controls.devicetests' from 'iPhone 11 Pro'
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[37mdbug�[39m�[22m�[49m: Running /Applications/Xcode_26.0.1.app/Contents/Developer/usr/bin/simctl
�[40m�[37mdbug�[39m�[22m�[49m: Process simctl exited with 0
�[40m�[32minfo�[39m�[22m�[49m: Application 'com.microsoft.maui.controls.devicetests' was uninstalled successfully
�[40m�[32minfo�[39m�[22m�[49m: <<XHARNESS_RESULT_START>>
{
"version": 1,
"machineName": "DK29L5WQYK-1",
"exitCode": 1,
"exitCodeName": "TESTS_FAILED",
"platform": "apple",
"device": "iPhone 11 Pro",
"deviceOsVersion": "26.0",
"files": [
{
"name": "test-ios-simulator-64_26.0-3CDB27E2-7E9A-4D1A-9B85-67243908FB66.log",
"type": "executionlog"
},
{
"name": "list-ios-simulator-64_26.0-20260529_073954.log",
"type": "devicelist"
},
{
"name": "test-ios-simulator-64_26.0-20260529_074002.log",
"type": "testlog"
},
{
"name": "iPhone 11 Pro.log",
"type": "systemlog"
},
{
"name": "Microsoft.Maui.Controls.DeviceTests.log",
"type": "systemlog"
},
{
"name": "com.microsoft.maui.controls.devicetests.log",
"type": "applicationlog"
},
{
"name": "xunit-test-ios-simulator-64_26.0-20260529_074002.xml",
"type": "xmllog"
}
]
}
<<XHARNESS_RESULT_END>>
XHarness exit code: 1 (TESTS_FAILED)
Passed: 0
Failed: 0
Tests completed with exit code: 1
🟢 With fix — 📱 AccessibilityTests (LayoutWithHintAndChildLabels_SynthesizesAccessibilityLabel, LayoutWithTapGesture_SetsShouldGroupAccessibilityChildren, AccessibilityActivate_InvokesTapGesture): PASS ✅ · 189s
(truncated to last 15,000 chars)
teAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4946740] 2026-05-29 07:43:42.494553-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Label'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4947500] 2026-05-29 07:43:42.494649-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Layout'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4948090] 2026-05-29 07:43:42.494698-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Lifecycle'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4949040] 2026-05-29 07:43:42.494797-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'ListView'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4950290] 2026-05-29 07:43:42.494881-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Map'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4950580] 2026-05-29 07:43:42.494935-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'MenuFlyout'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4951290] 2026-05-29 07:43:42.495032-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Mapper'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4952540] 2026-05-29 07:43:42.495115-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Excluded test (filtered by Trait; 'Category':'Memory'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4953400] 2026-05-29 07:43:42.495209-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Modal'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4955490] 2026-05-29 07:43:42.495324-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'NavigationPage'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4956130] 2026-05-29 07:43:42.495453-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Page'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4957070] 2026-05-29 07:43:42.495544-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Path'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4957790] 2026-05-29 07:43:42.495695-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Picker'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4959090] 2026-05-29 07:43:42.495774-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'RadioButton'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4959770] 2026-05-29 07:43:42.495875-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'RefreshView'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4961140] 2026-05-29 07:43:42.495918-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'ScrollView'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4963450] 2026-05-29 07:43:42.496113-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'SearchBar'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4964300] 2026-05-29 07:43:42.496285-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Shape'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4964570] 2026-05-29 07:43:42.496390-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Shell'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4966070] 2026-05-29 07:43:42.496433-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Slider'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4966890] 2026-05-29 07:43:42.496567-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'SwipeView'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4967630] 2026-05-29 07:43:42.496642-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'TabbedPage'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4967710] 2026-05-29 07:43:42.496691-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'TextInput'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4968520] 2026-05-29 07:43:42.496748-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Toolbar'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4969470] 2026-05-29 07:43:42.496819-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'TemplatedView'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4970750] 2026-05-29 07:43:42.496927-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'View'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4972010] 2026-05-29 07:43:42.497070-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'VisualElement'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4972730] 2026-05-29 07:43:42.497179-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'VisualElementTree'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4973640] 2026-05-29 07:43:42.497228-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'WebView'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4974340] 2026-05-29 07:43:42.497355-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Window'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4974800] 2026-05-29 07:43:42.497417-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'WindowOverlay'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.4975710] 2026-05-29 07:43:42.497450-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [FILTER] Included test (filtered by Trait; 'Category':'Xaml'): [Memory] TweenersWillNotLeakDuringInfiniteAnimation
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.5002040] 2026-05-29 07:43:42.500058-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [Test environment: 64-bit .NET .NET 10.0 [collection-per-class, non-parallel]]
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.5002200] 2026-05-29 07:43:42.500129-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [Test framework: xUnit.net 2.9.0.0]
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.5032280] 2026-05-29 07:43:42.503147-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213]
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:42.5032330] Serialize test because it has to add itself to the main window
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.3548500] 2026-05-29 07:43:43.354504-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [Unknown process name] clip: empty path.
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.3549000] 2026-05-29 07:43:43.354707-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [Unknown process name] clip: empty path.
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.3552380] 2026-05-29 07:43:43.355066-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [Unknown process name] clip: empty path.
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.4565720] 2026-05-29 07:43:43.456288-0700 Microsoft.Maui.Controls.DeviceTests[7628:52248] [default] Failed to resolve host network app id to config: bundleID: com.apple.WebKit.Networking instance ID: Optional([_EXExtensionInstanceIdentifier: B4CA8566-1045-4563-9603-2F57B25D985A])
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.5917760] 2026-05-29 07:43:43.591523-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] ValidateIsImportantForAccessibility
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.5944670] 2026-05-29 07:43:43.594187-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] Microsoft.Maui.DeviceTests.AccessibilityTests+InNewWindowCollection 1.0838532 ms
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.7895680] 2026-05-29 07:43:43.789003-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] Layout with TapGestureRecognizer (no Hint) sets ShouldGroupAccessibilityChildren
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.8727430] 2026-05-29 07:43:43.872498-0700 Microsoft.Maui.Controls.DeviceTests[7628:52302] [ProcessSuspension] WebContent[7629] 0x10b060100 - [sessionID=1] WebProcess::updateFreezerStatus: isFreezable=1, error=-1
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.9160990] 2026-05-29 07:43:43.915890-0700 Microsoft.Maui.Controls.DeviceTests[7628:52302] [AXRuntimeCommon] WebContent[7629] Could not register system wide server: -25204
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.9167550] 2026-05-29 07:43:43.916592-0700 Microsoft.Maui.Controls.DeviceTests[7628:52302] [AXRuntimeCommon] WebContent[7629] _AXAddToElementCache was called even though the element was in the cache: <WKAccessibilityWebPageObject: 0x600002100280>
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:43.9717480] 2026-05-29 07:43:43.971237-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] AccessibilityActivate on a layout with TapGestureRecognizer fires the gesture
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1723110] 2026-05-29 07:43:44.171783-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] Layout with Hint and child Labels synthesizes a combined AccessibilityLabel
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1726160] 2026-05-29 07:43:44.172409-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] Microsoft.Maui.DeviceTests.AccessibilityTests+Issue34380Tests 0.5733523 ms
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1732500] 2026-05-29 07:43:44.173131-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213]
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1732600] Test collection for Microsoft.Maui.DeviceTests.AccessibilityTests
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1815350] 2026-05-29 07:43:44.181225-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] IsInAccessibleTree initializes correctly
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1835750] 2026-05-29 07:43:44.183436-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] IsInAccessibleTree initializes correctly
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1856390] 2026-05-29 07:43:44.185513-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] ExcludedWithChildren initializes correctly
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1866690] 2026-05-29 07:43:44.186562-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] [PASS] ExcludedWithChildren initializes correctly
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1873410] 2026-05-29 07:43:44.187244-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] Microsoft.Maui.DeviceTests.AccessibilityTests 0.0094869 ms
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1887990] 2026-05-29 07:43:44.188695-0700 Microsoft.Maui.Controls.DeviceTests[7628:52270] Tests run: 8 Passed: 8 Inconclusive: 0 Failed: 0 Ignored: 0
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1916690] 2026-05-29 07:43:44.191370-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] Xml file was written to the provided writer.
�[40m�[37mdbug�[39m�[22m�[49m: [07:43:44.1917910] 2026-05-29 07:43:44.191582-0700 Microsoft.Maui.Controls.DeviceTests[7628:52213] Tests run: 450 Passed: 8 Inconclusive: 0 Failed: 0 Ignored: 442
�[40m�[37mdbug�[39m�[22m�[49m: ==================== End of ApplicationLog ====================
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[32minfo�[39m�[22m�[49m: Uninstalling the application 'com.microsoft.maui.controls.devicetests' from 'iPhone 11 Pro'
�[40m�[37mdbug�[39m�[22m�[49m:
�[40m�[37mdbug�[39m�[22m�[49m: Running /Applications/Xcode_26.0.1.app/Contents/Developer/usr/bin/simctl
�[40m�[37mdbug�[39m�[22m�[49m: Process simctl exited with 0
�[40m�[32minfo�[39m�[22m�[49m: Application 'com.microsoft.maui.controls.devicetests' was uninstalled successfully
�[40m�[32minfo�[39m�[22m�[49m: <<XHARNESS_RESULT_START>>
{
"version": 1,
"machineName": "DK29L5WQYK-1",
"exitCode": 0,
"exitCodeName": "SUCCESS",
"platform": "apple",
"device": "iPhone 11 Pro",
"deviceOsVersion": "26.0",
"files": [
{
"name": "test-ios-simulator-64_26.0-3CDB27E2-7E9A-4D1A-9B85-67243908FB66.log",
"type": "executionlog"
},
{
"name": "list-ios-simulator-64_26.0-20260529_074331.log",
"type": "devicelist"
},
{
"name": "test-ios-simulator-64_26.0-20260529_074337.log",
"type": "testlog"
},
{
"name": "iPhone 11 Pro.log",
"type": "systemlog"
},
{
"name": "Microsoft.Maui.Controls.DeviceTests.log",
"type": "systemlog"
},
{
"name": "com.microsoft.maui.controls.devicetests.log",
"type": "applicationlog"
},
{
"name": "xunit-test-ios-simulator-64_26.0-20260529_074337.xml",
"type": "xmllog"
}
]
}
<<XHARNESS_RESULT_END>>
XHarness exit code: 0
Passed: 8
Failed: 0
Tests completed successfully
📁 Fix files reverted (6 files)
eng/pipelines/ci-copilot.ymlsrc/Controls/src/Core/Platform/GestureManager/GesturePlatformManager.iOS.cssrc/Core/src/Platform/iOS/MauiView.cssrc/Core/src/Platform/iOS/SemanticExtensions.cssrc/Core/src/PublicAPI/net-ios/PublicAPI.Unshipped.txtsrc/Core/src/PublicAPI/net-maccatalyst/PublicAPI.Unshipped.txt
🧪 UI Tests — ViewBaseTests
Detected UI test categories: ViewBaseTests
✅ Deep UI tests — 112 passed, 0 failed across 1 category on platform-pool agent (replaces in-process counts above).
🧪 UI Test Execution Results (deep, platform pool)
| Category | Tests | Snapshot diffs |
|---|---|---|
ViewBaseTests |
112/112 ✓ | — |
📎 Download drop-deep-uitests artifact (TRX + snapshot diffs) |
🔍 Pre-Flight — Context & Validation
Issue: #34380 - [iOS] VoiceOver does not correctly describe View with GestureRecognizers
PR: #35590 - [iOS] Fix VoiceOver dropping child labels on layouts with SemanticProperties.Hint or TapGestureRecognizer
Platforms Affected: iOS, MacCatalyst
Files Changed: 5 implementation, 1 test
Key Findings
- The issue reports that iOS VoiceOver does not announce tappable layout interaction, and adding SemanticProperties.Hint makes a layout a leaf accessibility element that hides child label text.
- The current PR fix synthesizes layout AccessibilityLabel from visible child IText/semantic descriptions when a layout has a hint, promotes the layout to IsAccessibilityElement, and updates heading traits.
- The current PR fix adds dynamic re-synthesis via MauiView.AccessibilityLabel, an AccessibilityActivateCallback path for tap gestures, and cleanup for null/cleared semantics.
- Prior inline review concerns about stale snapshots, hidden children, null semantics cleanup, and grouping state have been resolved in the latest PR code.
- Gate result was already completed separately and passed on iOS; gate/content.md was not created or overwritten by this loop.
Code Review Summary
Verdict: LGTM
Confidence: high
Errors: 0 | Warnings: 1 | Suggestions: 2
Key code review findings:
- Warning: Missing test coverage for the demotion path when both hint and description are cleared from a promoted layout.
- Suggestion: MauiView.cs references a transient PR review comment instead of a stable issue link.
- Suggestion: AccessibilityLabel setter behavior while SynthesizeAccessibilityLabelFromChildren is true could be documented for maintainers.
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #35590 | Synthesize parent layout AccessibilityLabel from child text in SemanticExtensions, promote layout to a leaf accessibility element, and route AccessibilityActivate to tap gestures via MauiView.AccessibilityActivateCallback. | PASSED (Gate) | SemanticExtensions.cs, GesturePlatformManager.iOS.cs, MauiView.cs, PublicAPI entries, iOS device tests | Original PR |
🔬 Code Review — Deep Analysis
Code Review — PR #35590
[iOS] Fix VoiceOver dropping child labels on layouts with SemanticProperties.Hint or TapGestureRecognizer
Independent Assessment
What this changes (from code alone):
-
SemanticExtensions.cs(iOS): TheUpdateSemantics(UIView, IView)public method gains a new code path forILayoutviews. When a layout has a non-emptyHint, it: synthesizes anAccessibilityLabelfrom visibleITextchildren (unlessDescriptionis explicitly set), setsIsAccessibilityElement = true, clearsShouldGroupAccessibilityChildren, applies the heading trait, and returns early — bypassing the generic internal path. Two cleanup paths were also added: one for whenSemanticsbecomes null (ClearValue), another for whenHintandDescriptionare both cleared while the layout was promoted. ASynthesizeAccessibilityLabelFromChildren/CollectChildrenTexthelper pair traverses the MAUI virtual view tree with a depth cap of 10. -
MauiView.cs(iOS): Two internal properties and two method overrides added:SynthesizeAccessibilityLabelFromChildren(bool) — when true, theAccessibilityLabelgetter re-synthesizes the label on each VoiceOver focus from the current child tree instead of returning a stored snapshot.AccessibilityActivateCallback(Func<bool>?) +AccessibilityActivate()override — letsGesturePlatformManagerinject a directSendTappedinvocation, bypassing UIKit's simulated-touch path.
-
GesturePlatformManager.iOS.cs: When aTapGestureRecognizeris detected on anILayout, optionally setsShouldGroupAccessibilityChildren = true(only ifIsAccessibilityElementis not already true), and registersAccessibilityActivateCallbackonMauiView. A newResetAccessibilityPromotionFlags()helper reverses both changes on cleanup (Dispose and gesture-collection-change path). -
AccessibilityTests.iOS.cs: Three new device tests covering: label synthesis, ShouldGroupAccessibilityChildren promotion, and VoiceOver activation wiring. -
PublicAPI.Unshipped.txt(iOS + Mac Catalyst): Three new public override entries forAccessibilityActivate()andAccessibilityLabel.get/set.
Inferred motivation: UIKit's flat accessibility model means a layout can be either a leaf element (VoiceOver reads it, hiding children) or a container (children are read individually). Previously MAUI set IsAccessibilityElement = true for layouts with Hint but never populated AccessibilityLabel, so VoiceOver read only the hint. The fix synthesizes the label from children to match Android's TalkBack behavior.
Reconciliation with PR Narrative
Author claims: iOS VoiceOver reads only the Hint on a layout, ignoring child labels, because AccessibilityLabel was never populated. The fix synthesizes the label from children and also adds a reliable VoiceOver activation path for TapGestureRecognizer on Catalyst.
Agreement/disagreement: My code-only assessment matches the author's root-cause analysis precisely. The "flat accessibility model" constraint and the description-vs-synthesized-label branching logic are correctly implemented. All four prior review issues (stale snapshot, hidden children included, ShouldGroupAccessibilityChildren state, null-semantics cleanup) were addressed in the current code.
Findings
⚠️ Warning — Missing test coverage for the demotion path
SemanticExtensions.cs lines 164–175 demote a layout back to IsAccessibilityElement = false when both Hint and Description are cleared (non-null Semantics object, empty/whitespace strings). This branch has no corresponding device test. A regression in this block (e.g., the ILayout guard or the SynthesizeAccessibilityLabelFromChildren reset) would be invisible until a user reports that VoiceOver keeps announcing a layout as a leaf element after its hint is removed.
Suggested test sketch:
// Set hint → assert promoted → clear hint → assert demoted
SemanticProperties.SetHint(layout, "tap");
// ... handler update ...
SemanticProperties.SetHint(layout, string.Empty);
// ... handler update ...
Assert.False(platformView.IsAccessibilityElement, "Should be demoted after hint cleared.");This is the only demote scenario not exercised by the three tests in AccessibilityTests.iOS.cs.
💡 Suggestion — Doc comment embeds a private PR review URL
MauiView.cs line 917:
/// See PR #35590 review comment r3291149230.Private GitHub review-comment URLs are opaque and decay in usefulness over time. Replace with a reference to the issue or a stable doc anchor:
/// See https://github.com/dotnet/maui/issues/34380 for context.💡 Suggestion — AccessibilityLabel setter behavior when SynthesizeAccessibilityLabelFromChildren = true is undocumented
MauiView.cs lines 937–938:
set => base.AccessibilityLabel = value;If SynthesizeAccessibilityLabelFromChildren = true and a non-null value is written via the setter, the getter silently ignores the stored value and returns the synthesized label instead. This is intentional (the flag takes priority), but is not mentioned in the SynthesizeAccessibilityLabelFromChildren or AccessibilityLabel XML docs. Since SynthesizeAccessibilityLabelFromChildren is internal this is unlikely to bite callers outside MAUI, but a brief note in the getter's <remarks> would help future maintainers.
Devil's Advocate
Against the approval:
- The
ShouldGroupAccessibilityChildrenstate can become desynchronized fromGesturePlatformManager's_setShouldGroupAccessibilityChildrenflag in the scenario: (1) gesture added first → flag captures default, (2) hint set →SemanticExtensionsforcesShouldGroupAccessibilityChildren = falsewhile the flag still says "we set it to true", (3)ClearValue(Hint)→IsAccessibilityElementis cleared butShouldGroupAccessibilityChildrenis not restored. The author addressed this in the existing review thread and the reasoning is sound:ShouldGroupAccessibilityChildren = truealone does not make a layout VoiceOver-focusable, so the inconsistency carries no user-visible consequence. I accept this reasoning. - The
AccessibilityActivateCallbackcan remain registered onMauiViewafterClearValue(HintProperty), becauseGesturePlatformManagerhas not seen a gesture-collection change. The layout is no longerIsAccessibilityElement, so VoiceOver cannot activate it directly — the orphaned callback is unreachable. Not a bug, just mild latent state. HasAccessibleTapGesturereturns only the firstTapGestureRecognizerwithNumberOfTapsRequired == 1. Multiple primary tap gestures on the same layout would result in only the first firing through VoiceOver. This is pre-existing behavior not introduced by this PR.
Against the concerns I raised:
- The missing demotion test is a coverage gap, not a correctness defect — the demotion logic itself is correct and exercised manually.
- The doc comment nit is cosmetic.
Verdict: LGTM
Confidence: high
Summary: The fix correctly solves the UIKit flat-accessibility-model problem: layouts with Hint now have a synthesized AccessibilityLabel that VoiceOver can read, the dynamic re-synthesis on each focus avoids stale announcements, and both cleanup paths (null semantics and cleared hint) restore default state. All prior review issues are resolved. CI is fully green (35/35 checks passed). The two 💡 suggestions and one
🔧 Fix — Analysis & Comparison
Fix Candidates
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| 1 | try-fix-1 | Move dynamic synthesized label and direct activation callback from broad MauiView to layout-specific LayoutView. | PASS | 5 files | Narrower blast radius than PR; passes iOS accessibility tests, but may not cover rare non-LayoutView ILayout platform views. |
| 2 | try-fix-2 | Static one-time label synthesis in SemanticExtensions; keep only MauiView.AccessibilityActivate callback. | PASS | 5 files | Smaller than PR, but expert self-review found stale-label risk for dynamic child text, visibility, or semantic changes. |
| 3 | try-fix-3 | UIKit grouping-only container; avoid leaf promotion and synthesized parent label. | FAIL | 2 files | Fails because grouping alone does not promote the hinted layout and does not provide reliable activation. |
| PR | PR #35590 | Dynamic child-label synthesis via MauiView.AccessibilityLabel, layout leaf promotion, grouping cleanup, and direct activation callback. | PASSED (Gate) | 5 implementation files + 1 test | Original PR; gate passed on iOS before this loop. |
Candidate Narratives
try-fix-1
- Approach: LayoutView-specific accessibility behavior.
- Test: PASS. Category=Accessibility iOS Controls device tests reported 8/8 passed.
- Learning: This is a plausible narrower alternative and is the only candidate that may be competitive with the PR. Its tradeoff is coverage risk for ILayout implementations not backed by LayoutView.
try-fix-2
- Approach: Static semantic-label synthesis during mapping.
- Test: PASS. Category=Accessibility iOS Controls device tests reported 8/8 passed.
- Learning: Passing tests are insufficient here. Expert review identified a major stale-label failure mode; the PR's dynamic getter is more robust.
try-fix-3
- Approach: UIKit grouping-only container.
- Test: FAIL. Final run reported 8 tests run, 6 passed, 2 failed.
- Failure analysis: The layout was not promoted to an accessibility element and AccessibilityActivate did not handle the tap gesture. This rules out a grouping-only solution.
Cross-Pollination
| Model/Reviewer | Round | New Ideas? | Details |
|---|---|---|---|
| code-review + maui-expert-reviewer | 1 | Yes | Suggested constraining blast radius to LayoutView, testing simpler static synthesis, and testing a UIKit grouping/container hypothesis. |
| code-review + maui-expert-reviewer | 2 | No | After the three candidates, remaining synthetic UIAccessibilityElement proxy approach was considered meaningfully different but too complex/risky for this targeted fix and not worth running. |
Exhausted: Yes
Selected Fix: Candidate #1 is the best alternative candidate; PR #35590 remains the safer selected fix overall. Candidate #1 passes and has narrower blast radius, but PR #35590 covers all MauiView-backed layout promotion paths and avoids Candidate #2's stale snapshot issue while passing the already completed gate. No alternative was demonstrably better than the PR's fix.
📋 Report — Final Recommendation
Comparative Analysis - PR #35590
Candidates Compared
| Rank | Candidate | Test Result | Assessment |
|---|---|---|---|
| 1 | pr |
PASS - gate passed on iOS | Best overall. Dynamic child-label synthesis avoids stale snapshots, layout promotion handles the VoiceOver leaf requirement, direct activation handles tap gestures, and cleanup paths are present. |
| 2 | pr-plus-reviewer |
PASS - same implementation as pr |
Expert review found no actionable source changes. Functionally equivalent to pr, with only a non-blocking suggestion for additional demotion/transition test coverage. |
| 3 | try-fix-1 |
PASS - iOS Accessibility device tests 8/8 | Strongest alternative. It narrows behavior to LayoutView, reducing blast radius, but risks missing rare ILayout platform views not backed by LayoutView; the PR covers the broader MauiView-backed layout promotion path. |
| 4 | try-fix-2 |
PASS - iOS Accessibility device tests 8/8 | Weaker despite passing tests. Static one-time label synthesis can become stale when child text, semantic descriptions, visibility, or layout children change after semantics are mapped. |
| 5 | try-fix-3 |
FAIL - iOS Accessibility device tests 6/8 | Must rank below passing candidates. UIKit grouping alone did not promote the hinted layout to the required accessibility element and did not reliably handle VoiceOver activation. |
Analysis
The submitted PR fix remains the safest candidate. It addresses the root VoiceOver behavior by making hinted layouts accessible as leaf elements while dynamically synthesizing a parent label from child text, and it adds a direct AccessibilityActivate callback path for tap gestures. This combination covers the two observed failure modes from the issue and avoids the stale-label problem found in try-fix-2.
try-fix-1 is a credible narrower alternative because it passed the same iOS accessibility test category and keeps the new override behavior on LayoutView. However, its narrower scope creates coverage risk for layout implementations that are not backed by LayoutView. The PR's broader MauiView-based hook is preferable because the gate already passed and no expert reviewer found a correctness issue with the broader placement.
pr-plus-reviewer is effectively the same as pr: the expert reviewer returned LGTM, wrote no inline findings, and only suggested optional extra regression coverage. Since it does not materially improve the implementation, it should not displace the raw PR fix as the selected candidate.
try-fix-3 failed regression tests and is therefore ranked below every passing candidate as required.
Winner
pr is the winning candidate. It passed the gate, has the most robust dynamic behavior, covers activation and cleanup, and no alternative demonstrated a better correctness/safety tradeoff.
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
On iOS and MacCatalyst, when a container layout (for example, VerticalStackLayout) has SemanticProperties.Hint set, with or without a TapGestureRecognizer, VoiceOver focuses the entire layout as a single accessibility element but reads only the Hint, ignoring all child label text.
On Android, TalkBack handles the same layout correctly by reading the child text followed by the hint.
Root Cause
iOS accessibility uses a flat accessibility model. A UIView can either behave as:
It cannot behave as both at the same time. The previous MAUI implementation in SemanticExtensions.UpdateSemantics marked layouts with Hint or Description as IsAccessibilityElement = true and assigned AccessibilityHint = Hint, but never populated AccessibilityLabel. As a result, VoiceOver read only the hint, while all child content was hidden because the layout became a leaf accessibility element.
Why Android is unaffected
Android accessibility uses a hierarchical accessibility model. TalkBack walks the native view tree and reads both parent and child accessibility content together.
For example, on a VerticalStackLayout with Hint = "more info" containing two labels, TalkBack naturally announces:
"[label1], [label2], more info". There is no parent/child exclusivity like on iOS. The MAUI Android implementation sets accessibility properties such as ContentDescription and ImportantForAccessibility per view, and TalkBack correctly combines them while traversing the tree.
Description of Change
SemanticExtensions.cs: For ILayout views with Hint set, the fix now populates AccessibilityLabel before promoting the layout to an accessibility element. If Description is provided, it is used directly as the label. Otherwise, the label is synthesized from child IText content. This allows VoiceOver to read both the layout content and the hint together as a single focus unit.
The fix also resets IsAccessibilityElement back to false when both Hint and Description are later cleared from the layout.
GesturePlatformManager.iOS.cs: The existing ShouldGroupAccessibilityChildren value is now captured before modification and restored during cleanup.
Also added an AccessibilityActivateCallback registration on MauiView to improve MacCatalyst Ctrl+Option+Space tap reliability, since UIKit’s default activation path is unreliable on Catalyst.
MauiView.cs: Added AccessibilityActivateCallback : Func? and overrode AccessibilityActivate() so the callback can invoke TapGestureRecognizer.SendTapped() directly.
Issues Fixed
Fixes #34380
Screenshots
iOS:
34380BeforeFix.mov
34380AfterFix.mov
Mac:
34380MacBeforeFix.mov
34380MacAfterFix.mov